import sys
import sqlite3
from datetime import datetime, timezone
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

class MemoryApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.db = sqlite3.connect('cards.db')
        self.init_db()
        self.current_card = None
        self.answer_visible = False
        self.init_ui()
        self.load_next_card()
        self.current_tag_filter = None  # 当前筛选的标签
        self.filtered_cards = []        # 筛选后的卡片列表
        self.current_card_index = -1    # 当前卡片索引

    def init_db(self):
        c = self.db.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS cards
            (id INTEGER PRIMARY KEY, question TEXT, answer TEXT, 
             proficiency INTEGER DEFAULT 0, next_review DATETIME, 
             interval INTEGER DEFAULT 1, modified DATETIME)''')
        c.execute('''CREATE TABLE IF NOT EXISTS tags
            (id INTEGER PRIMARY KEY, name TEXT UNIQUE)''')
        c.execute('''CREATE TABLE IF NOT EXISTS card_tags
            (card_id INTEGER, tag_id INTEGER,
             FOREIGN KEY(card_id) REFERENCES cards(id),
             FOREIGN KEY(tag_id) REFERENCES tags(id))''')
        self.db.commit()

    def init_ui(self):
        self.setWindowTitle('记忆卡片 Pro')
        self.setGeometry(300, 300, 800, 600)
        
        central = QWidget()
        self.setCentralWidget(central)
        layout = QVBoxLayout(central)
        
        self.tags_label = QLabel()
        self.tags_label.setStyleSheet("color: #666; font-size: 12px;")
        layout.addWidget(self.tags_label)
        
        self.card_display = QTextEdit()
        self.card_display.setReadOnly(True)
        self.card_display.setStyleSheet("""
            QTextEdit {
                font-size: 20px;
                padding: 30px;
                border: 2px solid #eee;
                border-radius: 10px;
                margin: 15px;
            }
        """)
        layout.addWidget(self.card_display)
        
        btn_layout = QHBoxLayout()
        self.add_btn = self.create_button("添加 (A)", self.add_card)
        self.edit_btn = self.create_button("编辑 (D)", self.edit_card)
        self.prev_btn = self.create_button("上一个 (Q)", self.prev_card)
        self.next_btn = self.create_button("下一个 (E)", self.next_card)
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.edit_btn)
        btn_layout.addWidget(self.prev_btn)
        btn_layout.addWidget(self.next_btn)
        layout.addLayout(btn_layout)
        
        self.status = self.statusBar()
        self.update_status()
        
        self.shortcut_edit = QShortcut(QKeySequence("D"), self)
        self.shortcut_edit.activated.connect(self.edit_card)
        QShortcut(Qt.Key_Space, self).activated.connect(self.toggle_answer)
        QShortcut(Qt.Key_Q, self).activated.connect(self.prev_card)
        QShortcut(Qt.Key_E, self).activated.connect(self.next_card)
        QShortcut(Qt.Key_A, self).activated.connect(self.add_card)

        self.start_btn = self.create_button("开始学习 (S)", self.start_study_session)
        btn_layout.insertWidget(0, self.start_btn)
        QShortcut(Qt.Key_S, self).activated.connect(self.start_study_session)

    def create_button(self, text, callback):
        btn = QPushButton(text)
        btn.setStyleSheet("padding: 8px; background: #f0f0f0;")
        btn.clicked.connect(callback)
        return btn

    def add_card(self):
        dialog = CardEditDialog("", "", [], self.get_all_tags(), self)
        if dialog.exec_() == QDialog.Accepted:
            question, answer, tags = dialog.get_data()
            c = self.db.cursor()
            current_time = datetime.now(timezone.utc).isoformat()
            c.execute('''INSERT INTO cards 
                        (question, answer, next_review, modified)
                        VALUES (?, ?, ?, ?)''', 
                     (question, answer, current_time, current_time))
            card_id = c.lastrowid
            self.update_card_tags(card_id, tags)
            self.db.commit()
            self.load_next_card()

    def edit_card(self):
        if not self.current_card:
            return
            
        dialog = CardEditDialog(
            self.current_card[1], 
            self.current_card[2],
            self.get_card_tags(self.current_card[0]),
            self.get_all_tags(),
            self
        )
        if dialog.exec_() == QDialog.Accepted:
            question, answer, tags = dialog.get_data()
            c = self.db.cursor()
            c.execute('''UPDATE cards SET question=?, answer=?, modified=?
                      WHERE id=?''', 
                     (question, answer, datetime.now(), self.current_card[0]))
            self.update_card_tags(self.current_card[0], tags)
            self.db.commit()
            self.load_next_card()

    def update_card_tags(self, card_id, new_tags):
        c = self.db.cursor()
        c.execute("DELETE FROM card_tags WHERE card_id=?", (card_id,))
        for tag_id in new_tags:
            c.execute("INSERT INTO card_tags VALUES (?, ?)", (card_id, tag_id))
        self.db.commit()

    def get_all_tags(self):
        c = self.db.cursor()
        c.execute("SELECT id, name FROM tags ORDER BY name")
        return c.fetchall()

    def get_card_tags(self, card_id):
        c = self.db.cursor()
        c.execute('''SELECT t.id, t.name FROM tags t
                   JOIN card_tags ct ON t.id = ct.tag_id
                   WHERE ct.card_id = ?''', (card_id,))
        return c.fetchall()

    def load_next_card(self):
        c = self.db.cursor()
        c.execute('''SELECT * FROM cards 
                   WHERE next_review <= datetime('now') 
                   ORDER BY proficiency, RANDOM() LIMIT 1''')
        self.current_card = c.fetchone()
        self.answer_visible = False
        self.update_display()

    def update_display(self):
        if self.current_card:
            text = self.current_card[1] if not self.answer_visible else \
                  f"{self.current_card[1]}\n\n——\n{self.current_card[2]}"
            tags = self.get_card_tags(self.current_card[0])
            self.tags_label.setText("标签: " + ", ".join(t[1] for t in tags))
        else:
            text = "无待复习卡片"
        self.card_display.setText(text)
        self.update_status()

    def update_status(self):
        c = self.db.cursor()
        c.execute("SELECT COUNT(*) FROM cards")
        total = c.fetchone()[0]
        c.execute("SELECT COUNT(*) FROM cards WHERE next_review <= datetime('now')")
        due = c.fetchone()[0]
        p = self.current_card[4] if self.current_card else 0
        self.status.showMessage(f"总卡片: {total} | 待复习: {due} | 当前熟练度: {p}%")

    def toggle_answer(self):
        if self.current_card:
            self.answer_visible = not self.answer_visible
            self.update_display()

    def prev_card(self):
        if self.current_card:
            c = self.db.cursor()
            c.execute('SELECT * FROM cards WHERE id < ? ORDER BY id DESC LIMIT 1',
                     (self.current_card[0],))
            self.current_card = c.fetchone()
            self.answer_visible = False
            self.update_display()
    
    def start_study_session(self):
        # 弹出标签选择对话框
        tags = self.get_all_tags()
        if not tags:
            QMessageBox.information(self, "提示", "请先创建标签")
            return

        tag_names = [t[1] for t in tags]
        selected_tag, ok = QInputDialog.getItem(
            self, "选择标签", "请选择要学习的标签:", tag_names, editable=False
        )
        if ok and selected_tag:
            self.current_tag_filter = selected_tag
            self.load_filtered_cards()
            if self.filtered_cards:
                self.current_card_index = 0
                self.show_current_card()
            else:
                QMessageBox.information(self, "提示", "该标签下无待复习卡片")

    def load_filtered_cards(self):
        c = self.db.cursor()
        query = '''SELECT c.* FROM cards c
                   JOIN card_tags ct ON c.id = ct.card_id
                   JOIN tags t ON ct.tag_id = t.id
                   WHERE t.name = ? AND c.next_review <= datetime('now')
                   ORDER BY c.proficiency, RANDOM()'''
        c.execute(query, (self.current_tag_filter,))
        self.filtered_cards = c.fetchall()

    def show_current_card(self):
        if 0 <= self.current_card_index < len(self.filtered_cards):
            self.current_card = self.filtered_cards[self.current_card_index]
            self.answer_visible = False
            self.update_display()
            self.update_status()

    def next_card(self):
        if self.current_tag_filter:
            if self.current_card_index < len(self.filtered_cards) - 1:
                self.current_card_index += 1
                self.show_current_card()
            else:
                self.load_filtered_cards()
                if self.filtered_cards:
                    self.current_card_index = 0
                    self.show_current_card()
        else:
            self.load_next_card()

    # 增强状态显示
    def update_status(self):
        status = []
        if self.current_tag_filter:
            status.append(f"当前标签: {self.current_tag_filter}")
            status.append(f"进度: {self.current_card_index+1}/{len(self.filtered_cards)}")
        
        c = self.db.cursor()
        c.execute("SELECT COUNT(*) FROM cards")
        total = c.fetchone()[0]
        c.execute("SELECT COUNT(*) FROM cards WHERE next_review <= datetime('now')")
        due = c.fetchone()[0]
        
        status.append(f"总卡片: {total}")
        status.append(f"待复习: {due}")
        if self.current_card:
            status.append(f"熟练度: {self.current_card[4]}%")
        
        self.status.showMessage(" | ".join(status))

    # 修改评分逻辑
    def rate_card(self, rating):
        if not self.current_card:
            return
        
        # 更新卡片数据
        p = self.current_card[4]
        interval = self.current_card[5]
        
        if rating == 1:
            p = max(0, p - 20)
            interval = 1
        elif rating == 2:
            p = min(100, p + 15)
            interval = max(1, int(interval * 1.5))
        elif rating == 3:
            p = min(100, p + 30)
            interval = max(1, int(interval * 2))
        
        next_review = datetime.now(timezone.utc) + timedelta(days=interval)
        
        # 更新数据库
        c = self.db.cursor()
        c.execute('''UPDATE cards SET proficiency=?, interval=?, next_review=?
                  WHERE id=?''',
                 (p, interval, next_review.isoformat(), self.current_card[0]))
        self.db.commit()
        
        # 更新本地数据
        if self.current_tag_filter:
            # 从过滤列表中移除已评分卡片
            self.filtered_cards.pop(self.current_card_index)
            if self.filtered_cards:
                self.current_card_index = min(self.current_card_index, len(self.filtered_cards)-1)
                self.show_current_card()
            else:
                self.current_card = None
                self.update_display()
        else:
            self.load_next_card()

    # 增强键盘事件处理
    def keyPressEvent(self, event: QKeyEvent):
        if event.key() == Qt.Key_Space:
            self.toggle_answer()
        elif event.key() in (Qt.Key_1, Qt.Key_2, Qt.Key_3):
            self.rate_card(event.key() - Qt.Key_0)
        elif event.key() == Qt.Key_Q:
            self.prev_card()
        elif event.key() == Qt.Key_E:
            self.next_card()
        elif event.key() == Qt.Key_S:
            self.start_study_session()
        else:
            super().keyPressEvent(event)

    def prev_card(self):
        # 学习模式下的导航
        if self.current_tag_filter:
            if self.current_card_index > 0:
                self.current_card_index -= 1
                self.show_current_card()
            else:
                QMessageBox.information(self, "提示", "已经是第一张卡片")
        # 普通模式下的导航
        else:
            if self.current_card:
                c = self.db.cursor()
                # 查找比当前ID小的最近卡片
                c.execute('''SELECT * FROM cards 
                          WHERE id < ? 
                          ORDER BY id DESC 
                          LIMIT 1''', (self.current_card[0],))
                prev_card = c.fetchone()
                if prev_card:
                    self.current_card = prev_card
                    self.answer_visible = False
                    self.update_display()
                else:
                    QMessageBox.information(self, "提示", "已经是第一张卡片")

    def next_card(self):
        # 学习模式下的导航
        if self.current_tag_filter:
            # 还有后续卡片
            if self.current_card_index < len(self.filtered_cards) - 1:
                self.current_card_index += 1
                self.show_current_card()
            # 到达列表末尾尝试重新加载
            else:
                self.load_filtered_cards()
                if self.filtered_cards:
                    self.current_card_index = 0
                    self.show_current_card()
                    QMessageBox.information(self, "提示", "已重新加载当前标签卡片")
                else:
                    self.exit_study_mode()
                    QMessageBox.information(self, "提示", "该标签下已无更多卡片")
        # 普通模式下的导航
        else:
            self.load_next_card()

    def load_next_card(self):
        """普通模式加载下一张卡片"""
        c = self.db.cursor()
        query = '''SELECT * FROM cards 
                  WHERE next_review <= datetime('now') 
                  ORDER BY proficiency, RANDOM() 
                  LIMIT 1'''
        c.execute(query)
        new_card = c.fetchone()

        # 如果有新卡片
        if new_card:
            self.current_card = new_card
        # 没有新卡片但存在历史记录
        elif self.current_card:  
            c.execute('''SELECT * FROM cards 
                       ORDER BY next_review 
                       LIMIT 1''')
            self.current_card = c.fetchone()

        self.answer_visible = False
        self.update_display()

    def exit_study_mode(self):
        """退出学习模式"""
        self.current_tag_filter = None
        self.filtered_cards = []
        self.current_card_index = -1
        self.load_next_card()  # 回到普通模式
        self.update_status()

    def next_card(self):
        self.load_next_card()

    def closeEvent(self, event):
        self.db.close()

class CardEditDialog(QDialog):
    def __init__(self, question, answer, current_tags, all_tags, parent=None):
        super().__init__(parent)
        self.setWindowTitle("编辑卡片")
        self.setFixedSize(500, 400)
        
        layout = QVBoxLayout()
        
        self.question_edit = QTextEdit()
        self.question_edit.setPlainText(question)
        self.question_edit.setPlaceholderText("输入问题...")
        layout.addWidget(QLabel("问题:"))
        layout.addWidget(self.question_edit)
        
        self.answer_edit = QTextEdit()
        self.answer_edit.setPlainText(answer)
        self.answer_edit.setPlaceholderText("输入答案...")
        layout.addWidget(QLabel("答案:"))
        layout.addWidget(self.answer_edit)
        
        self.tag_widget = TagSelector(current_tags, all_tags)
        layout.addWidget(QLabel("标签:"))
        layout.addWidget(self.tag_widget)
        
        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(self.accept)
        btn_box.rejected.connect(self.reject)
        layout.addWidget(btn_box)
        
        self.setLayout(layout)

    def get_data(self):
        return (
            self.question_edit.toPlainText().strip(),
            self.answer_edit.toPlainText().strip(),
            self.tag_widget.selected_tags()
        )

class TagSelector(QWidget):
    def __init__(self, current_tags, all_tags):
        super().__init__()
        self.all_tags = {t[1]: t[0] for t in all_tags}
        self.current_tag_ids = {t[0] for t in current_tags}
        
        layout = QHBoxLayout()
        self.tag_list = QListWidget()
        self.tag_list.setSelectionMode(QListWidget.MultiSelection)
        self.load_tags(all_tags)
        layout.addWidget(self.tag_list)
        
        self.new_tag_edit = QLineEdit()
        self.new_tag_edit.setPlaceholderText("新建标签...")
        self.new_tag_btn = QPushButton("+")
        self.new_tag_btn.clicked.connect(self.create_tag)
        
        v_layout = QVBoxLayout()
        v_layout.addWidget(self.new_tag_edit)
        v_layout.addWidget(self.new_tag_btn)
        layout.addLayout(v_layout)
        
        self.setLayout(layout)

    def load_tags(self, tags):
        self.tag_list.clear()
        for tag_id, name in tags:
            item = QListWidgetItem(name)
            item.setData(Qt.UserRole, tag_id)
            item.setSelected(tag_id in self.current_tag_ids)
            self.tag_list.addItem(item)

    def create_tag(self):
        name = self.new_tag_edit.text().strip()
        if name and name not in self.all_tags:
            c = self.parent().parent().db.cursor()
            c.execute("INSERT INTO tags (name) VALUES (?)", (name,))
            c.connection.commit()
            self.all_tags[name] = c.lastrowid
            self.load_tags([(self.all_tags[name], name)])

    def selected_tags(self):
        return [item.data(Qt.UserRole) 
                for item in self.tag_list.selectedItems()]

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    window = MemoryApp()
    window.show()
    sys.exit(app.exec_())